﻿namespace ImageProcessing.Forms
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;

    /// <summary>
    /// Convolution Form
    /// </summary>
    public partial class ConvolutionForm : Form
    {
        /// <summary>
        /// Mask height
        /// </summary>
        private int maskHeigth = 0;

        /// <summary>
        /// Mask width
        /// </summary>
        private int maskwidth = 0;

        /// <summary>
        /// Mask array
        /// </summary>
        private double[,] mask;

        /// <summary>
        /// Original image
        /// </summary>
        private ImageStructure[,] orginal;

        /// <summary>
        /// Boolean to check state of mask
        /// </summary>
        private bool stateMask = false;

        /// <summary>
        /// Initializes a new instance of the <see cref="ConvolutionForm"/> class.
        /// </summary>
        public ConvolutionForm()
        {
            this.InitializeComponent();
            Main.ImageList[Main.CurrImage].BackupImageArray();
            this.orginal = ResizeImage.BicubicResize(this.PcbOriginal.Width, this.PcbOriginal.Height, Main.ImageList[Main.CurrImage].ImageStructArray, 2);
            this.PcbOriginal.Image = Operations.DisplayMatrix(Main.ImageList[Main.CurrImage].ImageStructArray);
            this.PcbNewImage.Image = Operations.DisplayMatrix(Main.ImageList[Main.CurrImage].ImageStructArray);
            this.CmbPostProcess.Items.Add("Cut Off");
            this.CmbPostProcess.Items.Add("Normalization");
            this.CmbPostProcess.SelectedIndex = 1;
        }

        /// <summary>
        /// Handles the TextChanged event of the TxtHiegth control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void TxtHiegth_TextChanged(object sender, EventArgs e)
        {
            int heigth;
            bool isNum = int.TryParse(this.TxtHiegth.Text, out heigth);

            if (isNum)
            {
                if (heigth % 2 == 0)
                {
                    this.errorProviderHiegth.SetError(this.TxtHiegth, "must be odd value");
                }
                else
                {
                    this.errorProviderHiegth.SetError(this.TxtHiegth, string.Empty);
                    this.maskHeigth = heigth;
                    if (this.maskwidth != 0)
                    {
                        this.dataGridMask.RowCount = this.maskHeigth;
                        this.dataGridMask.ColumnCount = this.maskwidth;
                        this.stateMask = true;
                    }
                }
            }
            else if (this.TxtHiegth.Text == string.Empty)
            {
                this.errorProviderHiegth.SetError(this.TxtHiegth, string.Empty);
                this.stateMask = false;
            }
            else
            {
                this.errorProviderHiegth.SetError(this.TxtHiegth, "invalde number");
                this.stateMask = false;
            }
        }

        /// <summary>
        /// Handles the TextChanged event of the TxtWidth control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void TxtWidth_TextChanged(object sender, EventArgs e)
        {
            int width;
            bool isNum = int.TryParse(this.TxtWidth.Text, out width);

            if (isNum)
            {
                if (width % 2 == 0)
                {
                    this.errorProviderWidth.SetError(this.TxtWidth, "must be odd value");
                }
                else
                {
                    this.errorProviderWidth.SetError(this.TxtWidth, string.Empty);
                    this.maskwidth = width;
                    if (this.maskHeigth != 0)
                    {
                        this.dataGridMask.RowCount = this.maskHeigth;
                        this.dataGridMask.ColumnCount = this.maskwidth;
                        this.stateMask = true;
                    }
                }
            }
            else if (this.TxtWidth.Text == string.Empty)
            {
                this.errorProviderWidth.SetError(this.TxtWidth, string.Empty);
                this.stateMask = false;
            }
            else
            {
                this.errorProviderWidth.SetError(this.TxtWidth, "Invalid number");
                this.stateMask = false;
            }
        }

        /// <summary>
        /// Handles the Click event of the BtnRunMask control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void BtnRunMask_Click(object sender, EventArgs e)
        {
            this.mask = new double[this.dataGridMask.RowCount, this.dataGridMask.ColumnCount];
            for (int i = 0; i < this.dataGridMask.RowCount; i++)
            {
                for (int j = 0; j < this.dataGridMask.ColumnCount; j++)
                {
                    this.mask[i, j] = Convert.ToDouble(this.dataGridMask.Rows[i].Cells[j].Value);
                }
            }

            switch (this.CmbPostProcess.SelectedIndex)
            {
                case 0:
                    this.PcbNewImage.Image = Operations.DisplayMatrix(NeighborhoodOperations.Convolution(Main.ImageList[Main.CurrImage].ImageStructArray, this.mask, PostProcessing.CuttOff, AddingType.Black));
                    break;
                case 1:
                    this.PcbNewImage.Image = Operations.DisplayMatrix(NeighborhoodOperations.Convolution(Main.ImageList[Main.CurrImage].ImageStructArray, this.mask, PostProcessing.Normalization, AddingType.Black));
                    break;
            }
        }

        /// <summary>
        /// Handles the Click event of the BtnCancel control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void BtnCancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        /// <summary>
        /// Handles the Click event of the BtnOk control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void BtnOk_Click(object sender, EventArgs e)
        {
            switch (this.CmbPostProcess.SelectedIndex)
            {
                case 0:
                    this.PcbNewImage.Image = Operations.DisplayMatrix(NeighborhoodOperations.Convolution(Main.ImageList[Main.CurrImage].ImageStructArray, this.mask, PostProcessing.CuttOff, AddingType.Black));
                    Main.OperationName = "Convolution operation. Mask H: " + this.mask.GetLength(0) + " W: " + this.mask.GetLength(1) + ". PostProcessing: cutoff!";                   
                    Main.ImageList[Main.CurrImage].UpdateImage(NeighborhoodOperations.Convolution(Main.ImageList[Main.CurrImage].ImageStructArray, this.mask, PostProcessing.CuttOff, AddingType.Black));
                    break;
                case 1:
                    this.PcbNewImage.Image = Operations.DisplayMatrix(NeighborhoodOperations.Convolution(Main.ImageList[Main.CurrImage].ImageStructArray, this.mask, PostProcessing.CuttOff, AddingType.Black));
                    Main.OperationName = "Convolution operation. Mask H: " + this.mask.GetLength(0) + " W: " + this.mask.GetLength(1) + ". PostProcessing: normalization!";                   
                    Main.ImageList[Main.CurrImage].UpdateImage(NeighborhoodOperations.Convolution(Main.ImageList[Main.CurrImage].ImageStructArray, this.mask, PostProcessing.Normalization, AddingType.Black));
                    break;
            }

            this.Close();
        }

        /// <summary>
        /// Handles the Click event of the BtnLoadMask control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void BtnLoadMask_Click(object sender, EventArgs e)
        {
            string fileName;
            OpenFileDialog browseFile = new OpenFileDialog();

            if (browseFile.ShowDialog() == DialogResult.Cancel)
            {
                return;
            }

            try
            {
                fileName = browseFile.FileName;
                this.mask = NeighborhoodOperations.LoadMak(fileName);

                this.dataGridMask.RowCount = this.mask.GetLength(0);
                this.dataGridMask.ColumnCount = this.mask.GetLength(1);
                for (int i = 0; i < this.dataGridMask.RowCount; i++)
                {
                    for (int j = 0; j < this.dataGridMask.ColumnCount; j++)
                    {
                        this.dataGridMask.Rows[i].Cells[j].Value = this.mask[i, j];
                    }
                }

                if (this.dataGridMask.RowCount > 0 && this.dataGridMask.ColumnCount > 0)
                {
                    this.stateMask = true;
                }
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
                MessageBox.Show("Error opening file", "File Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }

        /// <summary>
        /// Handles the Click event of the BtnSaveMask control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void BtnSaveMask_Click(object sender, EventArgs e)
        {
            if (!this.stateMask)
            {
                MessageBox.Show("Invalde width hiegth");
                return;
            }

            string fileName;
            SaveFileDialog saveeFile = new SaveFileDialog();

            if (saveeFile.ShowDialog() == DialogResult.Cancel)
            {
                return;
            }

            try
            {
                fileName = saveeFile.FileName + ".txt";
                NeighborhoodOperations.SaveMask(this.mask, fileName);
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
                MessageBox.Show("Error opening file", "File Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }

        /// <summary>
        /// Handles the CheckedChanged event of the checkBox1 control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void CheckBox1_CheckedChanged(object sender, EventArgs e)
        {
            if (this.stateMask)
            {
                this.mask = new double[this.dataGridMask.RowCount, this.dataGridMask.ColumnCount];
                for (int i = 0; i < this.dataGridMask.RowCount; i++)
                {
                    for (int j = 0; j < this.dataGridMask.ColumnCount; j++)
                    {
                        this.mask[i, j] = Convert.ToDouble(this.dataGridMask.Rows[i].Cells[j].Value);
                    }
                }
            }
            else
            {
                return;
            }

            if (this.CbxReview.Checked)
            {
                switch (this.CmbPostProcess.SelectedIndex)
                {
                    case 0:
                        this.PcbNewImage.Image = Operations.DisplayMatrix(ResizeImage.BicubicResize(this.PcbOriginal.Width, this.PcbOriginal.Height, NeighborhoodOperations.Convolution(Main.ImageList[Main.CurrImage].ImageStructArray, this.mask, PostProcessing.CuttOff, AddingType.Black), 2));

                        // PcbNewImage.Image = Operations.DisplayMatrix(NeighborhoodOperations.Convolution(this.orginal, mask, CutType.CuttOff, AddingType.Black));
                        Main.ImageList[Main.CurrImage].UpdateImage(NeighborhoodOperations.Convolution(Main.ImageList[Main.CurrImage].ImageStructArray, this.mask, PostProcessing.CuttOff, AddingType.Black));
                        break;
                    case 1:
                        this.PcbNewImage.Image = Operations.DisplayMatrix(ResizeImage.BicubicResize(this.PcbOriginal.Width, this.PcbOriginal.Height, NeighborhoodOperations.Convolution(Main.ImageList[Main.CurrImage].ImageStructArray, this.mask, PostProcessing.Normalization, AddingType.Black), 2));

                        // PcbNewImage.Image = Operations.DisplayMatrix(NeighborhoodOperations.Convolution(this.orginal, mask, CutType.CuttOff, AddingType.Black));
                        Main.ImageList[Main.CurrImage].UpdateImage(NeighborhoodOperations.Convolution(Main.ImageList[Main.CurrImage].ImageStructArray, this.mask, PostProcessing.Normalization, AddingType.Black));
                        break;
                }
            }
            else
            {
                Main.ImageList[Main.CurrImage].RetriveImageArray();
                this.PcbNewImage.Image = Operations.DisplayMatrix(this.orginal);
            }
        }

        /// <summary>
        /// Handles the SelectedIndexChanged event of the CmbPostProcess control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void CmbPostProcess_SelectedIndexChanged(object sender, EventArgs e)
        {
        }

        /// <summary>
        /// Handles the Load event of the ConvolutionForm control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void ConvolutionForm_Load(object sender, EventArgs e)
        {
        }
    }
}
